from flask import g, request
from wtforms import Form, StringField
import wtforms as wf
import wtforms.validators as vd
from app.libs.exception import AuthFailed, ParameterException
from app.libs.forms.validators import IDValidator, NullableEmailValidator, PathValidator, ResourceNameValidator, TypeValidator, UrlUnquote, VSSpeedValidator, VSStepValidator
from app.models.user import User
from app.service.token import TokenService
from app.libs.utils import Pager


class BaseForm(Form):
    ''' 
    统一处理Form错误信息
    when check_token is True， set g.current_user = user that is payload user
    '''
    LANGUAGES = ['zh']  # 并没有生效

    def __init__(self, check_token=True):
        """  when check_token is True， set g.current_user = user that is payload user """
        # data type : json form-data， 可以不需要传参数
        # args = request.args  # immutable dict # @RISK 还不支持URL传参的获取

        if check_token:
            g.current_user = self.__check_token_and_get_user()
            self.current_user = g.current_user
        data = request.get_json(silent=True)  # dict or None
        form_data = request.form  # immutable dict
        super().__init__(data=data, formdata=form_data, file=request.files.get('file'))

    @classmethod
    def __check_token_and_get_user(cls) -> User:
        token = request.headers.get(
            'token', default=None, type=str) or request.form.get('token', default=None)
        if not token:
            raise AuthFailed('请传入token再请求')
        user = TokenService.verify_jwt_and_get_user(token=token)
        return user  # 获取当前请求的用户信息

    def check_validate(self) -> Form:
        """ 质疑返回异常处理，而不需要手动处理 """
        valid = super(Form, self).validate()
        if not valid:
            raise ParameterException(msg=self.errors)
        return self

# token的校验是否集成到这


class TestForm(BaseForm):

    account = wf.StringField(
        validators=[vd.data_required(), vd.length(min=3, max=5)])
    path = wf.StringField(validators=[PathValidator()])


class IDForm(BaseForm):  # 传入ID的校验器
    id = wf.IntegerField(validators=[IDValidator()])


# 检验器
class RegisterForm(BaseForm):

    nickname = wf.StringField(validators=[vd.length(max=20)])
    account = wf.StringField(
        validators=[vd.data_required(), vd.length(min=4, max=20)])
    password = wf.StringField(
        validators=[vd.data_required(), vd.length(min=4, max=20)])
    email = wf.EmailField(validators=[NullableEmailValidator()])


class LoginForm(BaseForm):
    account = StringField(
        validators=[vd.DataRequired(), vd.Length(min=4, max=20)])
    password = wf.StringField(
        validators=[vd.DataRequired(), vd.Length(min=4, max=20)])


class requestForm(BaseForm):
    """ 用于校验请求的课程 | 视频 | 章节 信息 """
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(validators=[IDValidator()])


class SearchForm(BaseForm):

    key = wf.SearchField(validators=[vd.DataRequired(), vd.Length(max=30)])
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(
        validators=[IDValidator()])


class TypeForm(BaseForm):
    type = wf.IntegerField(validators=[TypeValidator()])


class VSConfigForm(BaseForm):
    step = wf.Field(validators=[VSStepValidator()], default=None)
    speed = wf.Field(validators=[VSSpeedValidator()], default=None)
    min_process_box_height = wf.IntegerField()
    min_searcher_box_with_height = wf.IntegerField()


class UploadPureVideoForm(BaseForm):
    file = wf.FileField(validators=[vd.data_required()])
    type = wf.IntegerField(validators=[TypeValidator()])
    # 可以传入一个对象进行校验，或者多个上传ConfigForm

    # def __init__(self):
    #     super().__init__(formdata=request.files, data=request.form)

    # def check_validate(self) -> Form:
    #     """ 质疑返回异常处理，而不需要手动处理 """
    #     valid = super(Form, self).validate()
    #     if not valid:
    #         raise ParameterException(msg=self.errors)
    #     return self
    vsConfigForm: VSConfigForm


class UploadByPathForm(BaseForm):
    path = wf.StringField(validators=[PathValidator()])
    type = wf.IntegerField(validators=[TypeValidator()])
    vsConfigForm: VSConfigForm


class ResourceByIDForm(BaseForm):
    # @RISK id的校验写的不好，如果增加了新的类型，无法判断，也需要大篇幅的修改
    type = wf.IntegerField(validators=[TypeValidator()])
    id = wf.IntegerField(validators=[IDValidator()])


class GetOneByUrlForm(BaseForm):
    url = wf.URLField(validators=[vd.url(), UrlUnquote()])
    type = wf.IntegerField(validators=[TypeValidator()])


class GetResourceListForm(BaseForm):
    type = wf.IntegerField(validators=[TypeValidator()])
    offset = wf.IntegerField(validators=[vd.number_range(min=0)], default=0)
    limit = wf.IntegerField(validators=[vd.number_range(min=0)], default=0)

    @property
    def pager(self) -> Pager:
        if hasattr(self, '_pager'):  # 单例模式
            return self._pager
        offset = self.data.get('offset')
        limit = self.data.get('limit')
        setattr(self, '_pager', Pager(offset, limit))
        return self._pager


# @MODIFYED 被 UploadPureVideoForm 替代
# class UploadFileForm(BaseForm):
#     file = wf.FileField(validators=[vd.data_required()])
#     type = wf.IntegerField(validators=[TypeValidator()])
#     # 可以传入一个对象进行校验，或者多个上传ConfigForm

#     # def __init__(self):
#     #     super().__init__(formdata=request.files, data=request.form)

#     # def check_validate(self) -> Form:
#     #     """ 质疑返回异常处理，而不需要手动处理 """
#     #     valid = super(Form, self).validate()
#     #     if not valid:
#     #         raise ParameterException(msg=self.errors)
#     #     return self
#     vsConfigForm: VSConfigForm


class UploadPureVideoForm(BaseForm):
    """ 
    type: 1 | 2 | 3  当 type为3, chapter_x和course_name都不能为空
    chapter_id
    course_id
    file: 视频文件对象
    """

    def __init__(self, vs_config_form: VSConfigForm, check_token=True):
        self.vsConfigForm = vs_config_form
        super().__init__(check_token=check_token)

    type = wf.IntegerField(validators=[TypeValidator()])
    file = wf.FileField(validators=[vd.data_required()])
    vsConfigForm: VSConfigForm
    chapter_id = wf.IntegerField(validators=[IDValidator(nullable=True)])
    course_id = wf.IntegerField(validators=[IDValidator(nullable=True)])
    # course_name = wf.StringField(validators=[ResourceNameValidator(True)])
    # chapter_name = wf.StringField(validators=[ResourceNameValidator(True)])


class CreateResourcePureForm(BaseForm):
    type = wf.IntegerField(validators=[TypeValidator()])
    course_id = wf.IntegerField(validators=[IDValidator(nullable=True)])
    name = wf.StringField(validators=[ResourceNameValidator(True)])
